#pragma once
#include<iostream>
#include<assert.h>
using namespace std;

namespace key
{
	class string
	{
	public:
		//构造函数
		string(const char* str = "")
		{
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity + 1];

			strcpy(_str, str);
		}
		//缺省函数 
		//既能string s1;
		//也能string s1("hello");



		//swap()函数
		void swap(string& s)
		{
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}

		//拷贝函数（现代写法）
		//string s1(s2);
		string(const string& s)
		{
			//用s（s2的引用）的_str去构造一个tmp对象
			string tmp(s._str);
			//然后用swap函数把tmp对象 和 *this 进行交换
			swap(tmp);
		}

		////拷贝函数（传统写法）
		//string(const string& s)
		//{
		//	_str = new char[s._capacity + 1];
		//	strcpy(_str, s._str);
		//	_size = s._size;
		//	_capacity = s._capacity;
		//}


		//赋值函数（现代写法）
		//s1 = s2;
		string& operator=(string s)
		{
			//该函数参数s去接受s2的时候，s2拷贝生成了s
			//直接swap 交换s 和 *this（s1）
			swap(s);
			return *this;
		}
		////赋值函数（传统写法）
		//string& operator=(const string& s)
		//{
		//	if (this != &s)
		//	{
		//		char* tmp = new char[s._capacity + 1];
		//		strcpy(tmp, s._str);
		//		delete[] _str;

		//		_str = tmp;
		//		_size = s._size;
		//		_capacity = s._capacity;
		//	}

		//	return *this;
		//}



		//析构函数
		~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = 0;
			_capacity = 0;
		}

		//以上是默认成员函数
		//---------------------------------------------------------

			//迭代器
			//可读可写的迭代器
		typedef char* iterator;
		//只可读不可写的迭代器
		typedef const char* const_iterator;

		//iterator用的begin()
		iterator begin()
		{
			return _str;
		}
		//iterator用的end()
		iterator end()
		{
			return _str + _size;
		}
		//const_iterator用的begin()
		const_iterator begin()const
		{
			return _str;

		}
		//const_iterator用的end()
		const_iterator end()const
		{
			return _str + _size;

		}


		//扩容函数
		//s1.reverse(10)
		void reserve(size_t n)
		{
			//vs的string类的reserve函数不支持缩容
			//所以我们为了保持一致，只对n>capacity进行扩容处理
			if (n > _capacity)
			{
				//开辟新的空间（n+1是因为多开一个给'/0'）
				char* tmp = new char[n + 1];
				//把旧空间的_str strcpy 到 tmp空间中
				strcpy(tmp, _str);
				//释放旧空间
				delete[] _str;
				//_str指向tmp
				_str = tmp;
				//容量重置成n
				_capacity = n;

			}

		}

		//c_str()函数
		const char* c_str() const//后面加const 对于是非const的对象都能调用
		{
			return _str;
		}

		//size函数()
		size_t size() const
		{
			//返回成员变量_size的值
			return _size;
		}

		////[]运算符重载(只可读)
		//const char operator[](size_t pos)const
		//{
		//	//'\0'也能读
		//	assert(pos <= _size);
		//	return _str[pos];
		//}
		//错误：忘加& 引用

		//[]运算符重载(只可读)
		const char& operator[](size_t pos)const
		{
			//'\0'也能读
			assert(pos <= _size);
			return _str[pos];

		}
		//对const类型的对象 返回值也必须是const 这叫权限一致

		////[]运算符重载(可读可写)
		//char operator[](size_t pos)
		//{
		//	assert(pos <= _size);
		//	return _str[pos];
		//}
		//错误：忘加& 引用


		//[]运算符重载(可读可写)
		char& operator[](size_t pos)
		{
			assert(pos <= _size);

			return _str[pos];
		}

		//find()函数 找字符
		//s1.('h',2)从下标为2开始查找 'h'字符
		size_t find(char c, size_t pos = 0)const
		{
			//assert(pos < _size);
			//遍历查找
			for (size_t i = pos; i < _size; i++)
			{
				if (_str[i] == c)
					return i;
			}
			//来到这里 代表找不到 返回npos（与库一致）
			return npos;
		}

		//find()函数 找字符串
		//s1.("hello",2)从下标为2开始查找 "hello"字符串
		size_t find(const char* str, size_t pos = 0)
		{
			//assert(pos < _size);
			//用strstr函数来从_str+pos位置开始查找字符串
			const char* ptr = strstr(_str + pos, str);
			//ptr为空 代表没找到 返回npos(于库一致)
			if (ptr == nullptr)
			{
				return npos;
			}
			else
			{
				//指针相减得到下标
				return ptr - _str;
			}
		}

		//erase()函数
		//s1.erase(2,5);从下标为2开始，清理5个字符
		void erase(size_t pos, size_t len = npos)
		{
			//断言
			assert(pos < _size);
			//不传len值，代表从pos位置开始全部清理
			//len + pos >= _size 也是从pos位置开始全部清理
			if (len == npos || len + pos >= _size)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else//代表从下标pos位置开始清理一部分
			{
				//将_str + pos + len往后的内容 strcpy到 _str + pos往后
				strcpy(_str + pos, _str + pos + len);
				//置_size-=len
				_size -= len;
			}

		}

		//clear()函数
		//s1.clear();
		void clear()
		{
			//_size置0 且 在第一个位置放入'\0'
			_size = 0;
			_str[0] = '\0';
		}

		//以上是一些工具函数
		//-----------------------------------------------------------------

		//尾插
		void push_back(char c)
		{
			//if判满
			if (_size == _capacity)
			{
				//两种满的给不同容量newcapacity
				size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
				//根据newcapacity扩容
				reserve(newcapacity);
			}
			//原先的_str[_size]是'\0'，现在成为新尾插的字符
			_str[_size] = c;
			//_size++
			_size++;
			//'\0'往后移动一个
			_str[_size] = '\0';
		}

		//append
		//s1.append("hello")
		void append(const char* str)
		{
			//计算出要追加的字符串的长度
			size_t len = strlen(str);
			//已有的字符串长度(_size)+len 超过容量即扩容
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
			//把追加的str strcpy 到 _str + _size 往后
			strcpy(_str + _size, str);
			//置_size+=len
			_size += len;
			//reserve里面已经置capacity

		}

		//+=运算符重载函数 
		//s1+='w' 给s1+=一个字符
		string& operator+=(char c)
		{
			//复用push_back()
			push_back(c);
			return *this;
		}

		//+=运算符重载函数
		//s1+="hello" 给s1+=一个字符串
		string& operator+=(const char* str)
		{
			//复用append()
			append(str);
			return *this;

		}



		//insert()函数 在下标为pos处插入字符
		//s1.insert(2,'w')在下标为2的位置，插入一个字符
		void insert(size_t pos, char c)
		{
			//断言 最多能在'\0'的位置插入数据
			assert(pos <= _size);
			//判满 与push_back类似
			if (_size == _capacity)
			{
				size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
				reserve(newcapacity);
			}

			//把下标从pos开始的所有字符向后移动一个
			size_t end = _size + 1;
			while (end > pos)
			{
				_str[end] = _str[end - 1];
				end--;
			}
			//腾出来的下标为pos的位置 给上要插入的字符
			_str[pos] = c;
			//_size++
			_size++;

		}


		//insert()函数 在下标为pos处插入字符串
		//s1.insert(2,"xxxx") 在下标为2处插入字符串"xxxx"
		void insert(size_t pos, const char* str)
		{
			//断言 最多能在'\0'的位置插入数据
			assert(pos <= _size);

			//判满 与append类似
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}

			//把下标从pos开始的所有字符向后移动len个
			size_t end = _size + len;
			while (end > pos)
			{
				_str[end] = _str[end - len];
				end--;
			}

			//把str的全部字符 复制到 s1的_str+pos处及往后的位置
			//strncpy 不计入'\0'
			strncpy(_str + pos, str, len);
			//置_size+=len
			_size += len;

		}

		///*substr()函数 截取_str的从下标为pos位置开始的len个字符作为一个新的对象
		//s1.substr(2,5)
		//string substr(size_t pos = 0, size_t len = npos)
		//{
		//	断言 不能从'\0'及以后的位置进行截取
		//	assert(pos < _size);

		//	截取字符串末尾下标为 end
		//	size_t end = len + pos;

		//	不传len值，代表从pos位置开始全部清理
		//	len + pos >= _size 也是从pos位置开始全部清理
		//	if (len == npos || len + pos >= _size)
		//	{
		//		end就变成了最后的位置('\0'的位置)
		//		end = _size;
		//	}

		//	end-pos 代表 从pos位置开始到最后一个字符的长度(不是'\0')
		//	reserve 会为'\0'多开一个空间

		//	建立一个新的对象
		//	string s2;
		//	新对象的空间为end-pos 大小不包含'\0'但是reserve里面会多开辟一个给'\0'
		//	s2.reserve(end - pos);

		//	把截取的字符串  让新对象str不断地+=字符
		//	for (size_t i = pos; i < end; i++)
		//	{
		//		s2 += _str[i];
		//	}
		//	return s2;
		//}
		// */
		//substr()函数 截取_str的从下标为pos位置开始的len个字符作为一个新的对象
		//s1.substr(2,5)
		string substr(size_t pos = 0, size_t len = npos)
		{

			assert(pos < _size);
			size_t end = len + pos;

			if (len == npos || len + pos >= _size)
			{
				end = _size;
			}

			string s2;
			s2.reserve(end - pos);

			for (size_t i = pos; i < end; i++)
			{
				s2 += _str[i];
			}
			return s2;
		}
		//以上是string的重要函数
		//--------------------------------------		

	private:

		size_t _size = 0;
		size_t _capacity = 0;
		char* _str = nullptr;
		static const size_t npos;

	};
	const size_t string::npos = -1;

	//<<运算符重载
	ostream& operator<<(ostream& out, const string& s)
	{
		for (size_t i = 0; i < s.size(); i++)
		{
			out << s[i];
		}
		cout << '\n';
		return out;

	}

	//>>运算符重载
	istream& operator>>(istream& in, string& s)
	{
		s.clear();
		char buff[128];
		char ch = in.get();
		int i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == 127)
			{
				buff[i] = '\0';
				s += buff;
				i = 0;
			}

			ch = in.get();
			if (i > 0)
			{
				buff[i] = '\0';
				s += buff;
			}
		}
		return in;

	}
	//流插入 流提取的运算符重载
	//-----------------------------------------------

	void test()
	{
		string s1;
		string s2("world");
		cout << "构造出的空s1:" << s1;
		cout << "构造出的s2:" << s2;
		cout << "使用+=，连续给s1+=字符" << endl;
		s1 += 'h';
		cout << s1;
		s1 += 'e';
		cout << s1;
		cout << "使用+=，给s1+=一个字符串llo " << endl;
		s1 += "llo";
		cout << "最终的的s1:" << s1;
		cout << endl;
		cout << endl;


		string s3 = s1;
		cout << "由s1拷贝得到的s3:" << s3;
		string s4 = s2;
		cout << "由s2拷贝得到的s4:" << s4;
		cout << endl;


		string s5;
		s5 = s1;
		string s6;
		s6 = s2;
		cout << "由s1赋值得到的s5:" << s5;
		cout << "由s2赋值得到的s6:" << s6;
		cout << endl;


		string s7("hello");
		cout << "打印正常非const对象s7:" << s7;
		const string s8("world");
		cout << "打印const对象s8:" << s8;
		cout << endl;


		//迭代器验证

		cout << "正常对象s7使用迭代器进行遍历打印:";
		string::iterator it = s7.begin();
		while (it != s7.end())
		{
			cout << *it;
			++it;
		}

		cout << endl;

		cout << "正常对象s7使用迭代器进行更改再打印:";
		string::iterator it2 = s7.begin();
		while (it2 != s7.end())
		{
			*it2 = 'x';
			cout << *it2;
			++it2;
		}
		cout << endl;
		cout << endl;


		cout << "const对象s8使用const迭代器进行遍历打印:";
		string::const_iterator it3 = s8.begin();
		while (it3 != s8.end())
		{
			cout << *it3;
			++it3;
		}

		cout << endl;

		//const对象s8无法进行写 
		/*cout << "const对象s8使用const迭代器进行遍历打印:";
		string::const_iterator it4 = s8.begin();
		while (it4 != s8.end())
		{
			*it4 = 'x';
			cout << *it;
			++it;
		}*/

		s1.swap(s2);
		cout << "用swap()函数交换s1和s2" << endl;
		cout << "交换后的s1:" << s1;
		cout << "交换后的s2:" << s2;
		cout << endl;

		cout << "在s1中找字符串rld" << endl;
		int pos = s1.find("rld");//不给pos 即从头开始找
		cout << "将下标给substr得到一个新的对象s9" << endl;

		string s9 = s1.substr(pos);//不传len 即从pos开始全部截取
		cout << "s9:" << s9;

		cout << "inset()函数在s9头插字符串wo：" << endl;
		s9.insert(0, "wo");
		cout << "s9:" << s9;

	}
}
